﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKRevitBase.Math;
using YJKRevitKernel.BoundingBoxUtility;

namespace YJKRevitKernel.RevitInteractiveUtility
{
	public class ElementsZoomUtility
	{
		public static void ZoomElement(UIDocument uiDoc, ElementId id, bool bIsHighlight = true)
		{
			if (null == id)
			{
				return;
			}
			uiDoc.ShowElements(id);
			if (bIsHighlight)
			{
				ElementsZoomUtility.HighlightElement(uiDoc, id);
			}
		}

		public static void ZoomElements(UIDocument uiDoc, List<ElementId> ids, bool bIsHighlight = true)
		{
			if (ids.Count == 0)
			{
				return;
			}
			uiDoc.ShowElements(ids);
			if (bIsHighlight)
			{
				RevitVersionFuncs.ClearSelection(uiDoc.Selection);
				List<Element> list = new List<Element>();
				foreach (ElementId elementId in ids)
				{
					list.Add(uiDoc.Document.GetElement(elementId));
				}
				RevitVersionFuncs.SetSelection(uiDoc.Selection, list);
				uiDoc.RefreshActiveView();
			}
		}

		public static void ZoomElement3d(UIDocument uiDoc, Element zoomElement, bool bIsHighlight = true, bool ifUseBoxMinZ = false, double? scale = null)
		{
			ElementsZoomUtility.ZoomElement3d(uiDoc, zoomElement, bIsHighlight, ifUseBoxMinZ, scale);
		}

		public static void ZoomElement3d(UIDocument uiDoc, List<Element> zoomElements, bool bIsHighlight = true, bool ifUseBoxMinZ = false, double? scale = null)
		{
			ElementsZoomUtility.ZoomElement3d(uiDoc, zoomElements, bIsHighlight, ifUseBoxMinZ, null);
		}

		public static void ZoomElement3dNoSection(UIDocument uiDoc, Element zoomElement, bool bIsHighlight = true, double? scale = null)
		{
			if (uiDoc == null || zoomElement == null)
			{
				return;
			}
			View3D view3D = null;
			Transaction transaction = new Transaction(uiDoc.Document);
			transaction.Start("ShowElement3d");
			try
			{
				view3D = ElementsZoomUtility.Get3DView(uiDoc, zoomElement, "临时三维视图", false, false, null);
				transaction.Commit();
			}
			catch
			{
				transaction.RollBack();
			}
			if (view3D != null)
			{
				uiDoc.ActiveView = view3D;
				uiDoc.RefreshActiveView();
				UIView activeUIView = ElementsZoomUtility.GetActiveUIView(uiDoc);
				if (activeUIView != null)
				{
					BoundingBoxXYZ element3dBox = ElementsZoomUtility.GetElement3dBox(uiDoc, zoomElement, false, scale);
					activeUIView.ZoomAndCenterRectangle(element3dBox.Min, element3dBox.Max);
				}
				if (bIsHighlight)
				{
					ElementsZoomUtility.HighlightElement(uiDoc, zoomElement.Id);
				}
			}
		}

		private static void ZoomElement3d(UIDocument uiDoc, object zoomElements, bool bIsHighlight = true, bool ifUseBoxMinZ = false, double? scale = null)
		{
			if (uiDoc == null || zoomElements == null)
			{
				return;
			}
			View3D view3D = null;
			Transaction transaction = new Transaction(uiDoc.Document);
			transaction.Start("ShowElement3d");
			try
			{
				view3D = ElementsZoomUtility.Get3DView(uiDoc, zoomElements, "临时三维视图", true, ifUseBoxMinZ, scale);
				transaction.Commit();
			}
			catch
			{
				transaction.RollBack();
			}
			if (view3D != null)
			{
				uiDoc.ActiveView = view3D;
				uiDoc.RefreshActiveView();
				UIView activeUIView = ElementsZoomUtility.GetActiveUIView(uiDoc);
				if (activeUIView != null)
				{
					BoundingBoxXYZ sectionBox = view3D.GetSectionBox();
					activeUIView.ZoomAndCenterRectangle(sectionBox.Min, sectionBox.Max);
				}
				if (bIsHighlight)
				{
					ElementsZoomUtility.HighlightElement(uiDoc, zoomElements);
				}
			}
		}

		private static BoundingBoxXYZ GetElement3dBox(UIDocument uiDoc, Element zoomElement, bool ifUseBoxMinZ = false, double? scale = null)
		{
			ViewPlan viewPlan = ElementsZoomUtility.GetViewPlan(uiDoc, zoomElement);
			BoundingBoxXYZ boundingBoxXYZ;
			if (viewPlan != null)
			{
				boundingBoxXYZ = zoomElement.get_BoundingBox(viewPlan);
			}
			else
			{
				boundingBoxXYZ = zoomElement.get_BoundingBox(uiDoc.ActiveView);
			}
			if (boundingBoxXYZ == null)
			{
				return null;
			}
			double num = UnitUtility.MMToFeet(300.0);
			double num2 = ElementsZoomUtility.GetElementLevelElevation(uiDoc, zoomElement, num);
			double num3 = boundingBoxXYZ.Max.Z + num;
			if (ifUseBoxMinZ)
			{
				num2 = boundingBoxXYZ.Min.Z;
				num3 = boundingBoxXYZ.Max.Z;
			}
			double num4 = UnitUtility.MMToFeet(5000.0);
			double num5 = boundingBoxXYZ.Min.X - num;
			double num6 = boundingBoxXYZ.Max.X + num;
			if (num6 - num5 < num4)
			{
				num5 -= 0.5 * num4;
				num6 += 0.5 * num4;
			}
			double num7 = boundingBoxXYZ.Min.Y - num;
			double num8 = boundingBoxXYZ.Max.Y + num;
			if (num8 - num7 < num4)
			{
				num7 -= 0.5 * num4;
				num8 += 0.5 * num4;
			}
			boundingBoxXYZ.Min = new XYZ(num5, num7, num2);
			boundingBoxXYZ.Max = new XYZ(num6, num8, num3);
			if (scale != null)
			{
				boundingBoxXYZ = BoundingBoxUtilityMethod.BoundingBox_Scale(boundingBoxXYZ, scale.Value);
			}
			return boundingBoxXYZ;
		}

		private static double GetElementLevelElevation(UIDocument uiDoc, Element zoomElement, double dOffset)
		{
			Level level = ElementsZoomUtility.GetLevel(uiDoc, zoomElement);
			if (level != null)
			{
				return level.Elevation;
			}
			ViewPlan viewPlan = ElementsZoomUtility.GetViewPlan(uiDoc, zoomElement);
			BoundingBoxXYZ boundingBoxXYZ;
			if (viewPlan != null)
			{
				boundingBoxXYZ = zoomElement.get_BoundingBox(viewPlan);
			}
			else
			{
				boundingBoxXYZ = zoomElement.get_BoundingBox(uiDoc.ActiveView);
			}
			double z = boundingBoxXYZ.Min.Z;
			foreach (Level level2 in ElementsZoomUtility.GetAllLevel(uiDoc.Document))
			{
				if (z > level2.Elevation)
				{
					return level2.Elevation;
				}
			}
			return z - dOffset;
		}

		private static List<Level> GetAllLevel(Autodesk.Revit.DB.Document doc)
		{
			List<Level> list = new List<Level>();
			foreach (Element element in new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).ToElements())
			{
				Level level = element as Level;
				if (level != null)
				{
					list.Add(level);
				}
			}
			list.Sort((Level l1, Level l2) => l2.Elevation.CompareTo(l1.Elevation));
			return list;
		}

		private static View3D Get3DView(UIDocument uiDoc, object zoomElement, string strViewName, bool bSetSection, bool ifUseBoxMinZ = false, double? scale = null)
		{
			if (zoomElement is List<Element>)
			{
				return ElementsZoomUtility.Get3DView(uiDoc, zoomElement as List<Element>, strViewName, bSetSection, ifUseBoxMinZ, scale);
			}
			return ElementsZoomUtility.Get3DView(uiDoc, zoomElement as Element, strViewName, bSetSection, ifUseBoxMinZ, scale);
		}

		private static View3D Get3DView(UIDocument uiDoc, Element zoomElement, string strViewName, bool bSetSection, bool ifUseBoxMinZ = false, double? scale = null)
		{
			BoundingBoxXYZ element3dBox = ElementsZoomUtility.GetElement3dBox(uiDoc, zoomElement, ifUseBoxMinZ, scale);
			if (element3dBox == null)
			{
				return null;
			}
			return ElementsZoomUtility.CreatView3D(uiDoc, strViewName, bSetSection, element3dBox);
		}

		private static View3D Get3DView(UIDocument uiDoc, List<Element> zoomElement, string strViewName, bool bSetSection, bool ifUseMinboxZ = false, double? scale = null)
		{
			List<BoundingBoxXYZ> list = new List<BoundingBoxXYZ>();
			foreach (Element zoomElement2 in zoomElement)
			{
				BoundingBoxXYZ element3dBox = ElementsZoomUtility.GetElement3dBox(uiDoc, zoomElement2, ifUseMinboxZ, scale);
				if (element3dBox != null)
				{
					list.Add(element3dBox);
				}
			}
			BoundingBoxXYZ boundingBoxXYZ = BoundingBoxUtilityMethod.BoundingBoxesMerge(list);
			if (boundingBoxXYZ == null)
			{
				return null;
			}
			return ElementsZoomUtility.CreatView3D(uiDoc, strViewName, bSetSection, boundingBoxXYZ);
		}

		private static View3D CreatView3D(UIDocument uiDoc, string strViewName, bool bSetSection, BoundingBoxXYZ bdBox)
		{
			View3D view3D = ElementsZoomUtility.Find3DView(uiDoc, strViewName);
			if (view3D == null)
			{
				XYZ direction = new XYZ(-1.0, 1.0, -1.0);
				view3D = RevitVersionFuncs.NewView3D(uiDoc.Document, direction);
				view3D.Name = strViewName;
				view3D.DetailLevel = (ViewDetailLevel)3;
                view3D.DisplayStyle = (DisplayStyle)3;
			}
			if (bSetSection)
			{
				view3D.SetYJKSectionBox(bdBox);
			}
			return view3D;
		}

		private static View3D Find3DView(UIDocument uiDoc, string strViewName)
		{
			FilteredElementIterator elementIterator = new FilteredElementCollector(uiDoc.Document).OfClass(typeof(Autodesk.Revit.DB.View)).GetElementIterator();
			elementIterator.Reset();
			while (elementIterator.MoveNext())
			{
				Element element = elementIterator.Current;
				Autodesk.Revit.DB.View view = element as Autodesk.Revit.DB.View;
				if (view != null && !view.IsTemplate && view is View3D && view.Name == strViewName)
				{
					return view as View3D;
				}
			}
			return null;
		}

		private static UIView GetActiveUIView(UIDocument uiDoc)
		{
			foreach (UIView uiview in uiDoc.GetOpenUIViews())
			{
				if (uiview.ViewId.Equals(uiDoc.ActiveView.Id))
				{
					return uiview;
				}
			}
			return null;
		}

		private static ViewPlan GetViewPlan(UIDocument uiDoc, Element zoomElement)
		{
			Level level = ElementsZoomUtility.GetLevel(uiDoc, zoomElement);
			if (level != null)
			{
				foreach (Element element in new FilteredElementCollector(uiDoc.Document).OfClass(typeof(ViewPlan)).ToElements().ToList<Element>())
				{
					ViewPlan viewPlan = element as ViewPlan;
					if (viewPlan.Name == level.Name)
					{
						return viewPlan;
					}
				}
			}
			return null;
		}

		private static Level GetLevel(UIDocument uiDoc, Element zoomElement)
		{
			if (zoomElement.LevelId.IntegerValue != -1)
			{
				Element elementById = uiDoc.GetElementById(zoomElement.LevelId);
				if (elementById != null)
				{
					return elementById as Level;
				}
			}
			Parameter parameter = zoomElement.GetParameter(BuiltInParameter.RBS_START_LEVEL_PARAM);
			if (parameter != null)
			{
				ElementId elementId = parameter.AsElementId();
				if (elementId.IntegerValue != -1)
				{
					Element elementById2 = uiDoc.GetElementById(elementId);
					if (elementById2 != null)
					{
						return elementById2 as Level;
					}
				}
			}
			double z = zoomElement.get_BoundingBox(uiDoc.ActiveView).Min.Z;
			foreach (Level level in ElementsZoomUtility.GetAllLevel(uiDoc.Document))
			{
				if (z > level.Elevation)
				{
					return level;
				}
			}
			return null;
		}

		private static void HighlightElement(UIDocument uiDoc, ElementId elemId)
		{
			Element element = uiDoc.Document.GetElement(elemId);
			if (element == null)
			{
				return;
			}
			if (element.Document.IsLinked)
			{
				return;
			}
			ElementsZoomUtility.ReSetSelection(uiDoc, new List<Element>
			{
				element
			});
		}

		private static void HighlightElement(UIDocument uiDoc, Element elem)
		{
			if (elem == null)
			{
				return;
			}
			if (elem.Document.IsLinked)
			{
				return;
			}
			ElementsZoomUtility.ReSetSelection(uiDoc, new List<Element>
			{
				elem
			});
		}

		private static void HighlightElement(UIDocument uiDoc, object elem)
		{
			if (elem is List<Element>)
			{
				ElementsZoomUtility.HighlightElement(uiDoc, elem as List<Element>);
				return;
			}
			if (elem is Element)
			{
				ElementsZoomUtility.HighlightElement(uiDoc, elem as Element);
				return;
			}
			ElementsZoomUtility.HighlightElement(uiDoc, elem as ElementId);
		}

		private static void HighlightElement(UIDocument uiDoc, List<Element> lstInputElments)
		{
			if (lstInputElments == null || lstInputElments.Count == 0)
			{
				return;
			}
			List<Element> list = new List<Element>();
			foreach (Element element in lstInputElments)
			{
				if (element != null && !element.Document.IsLinked)
				{
					list.Add(element);
				}
			}
			if (lstInputElments.Count == 0)
			{
				return;
			}
			ElementsZoomUtility.ReSetSelection(uiDoc, list);
		}

		private static void ReSetSelection(UIDocument uiDoc, List<Element> lstElement)
		{
			RevitVersionFuncs.ClearSelection(uiDoc.Selection);
			RevitVersionFuncs.SetSelection(uiDoc.Selection, lstElement);
			uiDoc.RefreshActiveView();
		}
	}
}
